﻿Imports System.IO

''' <summary>
''' Enum describes the screen transition state.
''' </summary>
Public Enum ScreenState
	TransitionOn
	Active
	TransitionOff
	Hidden
End Enum


''' <summary>
''' Screen adalah sebuah layer yang kerjanya ngupdate sama gambar logic
''' dimana dia bisa dikombinasikan dengan layer laun untuk menciptakan sebuah menu sistem yang kompleks
''' misal pada main menu, mesej box bertuliskan "are you sure want to quit?"
''' dan main game itu sendiri adalah implementasi dari banyak screen.
''' </summary>
Public MustInherit Class GameScreen
#Region "Properties"


	''' <summary>
	''' Biasanya, ketika satu screen ditaro diatas lainnya,
	''' screen yang pertama akan transition off untuk mebuka ruang buat screen yang baru.
	''' Properti ini menunjukkan bahwa screen cuma pop-up kecil.
	''' </summary>
	Public Property IsPopup As Boolean
		Get
			Return _isPopup
		End Get
		Protected Set(value As Boolean)
			_isPopup = value
		End Set
	End Property

	Dim _isPopup As Boolean = False


	''' <summary>
	''' Menunjukkan seberapa lama si screen melakukan transisi ketika dia diaktifkan.
	''' </summary>
	Public Property TransitionOnTime As TimeSpan
		Get
			Return _transitionOnTime
		End Get
		Protected Set(value As TimeSpan)
			_transitionOnTime = value
		End Set
	End Property

	Dim _transitionOnTime As TimeSpan = TimeSpan.Zero


	''' <summary>
	''' seberapa lama si screen melakukan transisi off ketika dia dinonaktifkan.
	''' </summary>
	Public Property TransitionOffTime As TimeSpan
		Get
			Return _transitionOffTime
		End Get
		Protected Set(value As TimeSpan)
			_transitionOffTime = value
		End Set
	End Property

	Dim _transitionOffTime As TimeSpan = TimeSpan.Zero


	''' <summary>
	''' Gets the current position of the screen transition, ranging
	''' from zero (fully active, no transition) to one (transitioned
	''' fully off to nothing).
	''' </summary>
	Public Property TransitionPosition!
		Get
			Return _transitionPosition
		End Get
		Protected Set(value!)
			_transitionPosition = value
		End Set
	End Property

	Dim _transitionPosition! = 1


	''' <summary>
	''' Gets the current alpha of the screen transition, ranging
	''' from 1 (fully active, no transition) to 0 (transitioned
	''' fully off to nothing).
	''' </summary>
	Public ReadOnly Property TransitionAlpha!
		Get
			Return 1.0F - TransitionPosition
		End Get
	End Property


	''' <summary>
	''' Gets the current screen transition state.
	''' </summary>
	Public Property ScreenState As ScreenState
		Get
			Return _screenState
		End Get
		Protected Set(value As ScreenState)
			_screenState = value
		End Set
	End Property

	Dim _screenState As ScreenState = ScreenState.TransitionOn


	''' <summary>
	''' There are two possible reasons why a screen might be transitioning
	''' off. It could be temporarily going away to make room for another
	''' screen that is on top of it, or it could be going away for good.
	''' This property indicates whether the screen is exiting for real:
	''' if set, the screen will automatically remove itself as soon as the
	''' transition finishes.
	''' </summary>
	Public Property IsExiting As Boolean
		Get
			Return _isExiting
		End Get
		Protected Friend Set(value As Boolean)
			_isExiting = value
		End Set
	End Property

	Dim _isExiting As Boolean = False


	''' <summary>
	''' Checks whether this screen is active and can respond to user input.
	''' </summary>
	Public ReadOnly Property IsActive As Boolean
		Get
			Return Not (otherScreenHasFocus) And _
			 (ScreenState = ScreenState.TransitionOn Or _
			  ScreenState = ScreenState.Active)
		End Get
	End Property

	Dim otherScreenHasFocus As Boolean


	''' <summary>
	''' Gets the manager that this screen belongs to.
	''' </summary>
	Public Property ScreenManager As ScreenManager
		Get
			Return _screenManager
		End Get
		Friend Set(value As ScreenManager)
			_screenManager = value
		End Set
	End Property

	Dim _screenManager As ScreenManager


	''' <summary>
	''' Gets the index of the player who is currently controlling this screen,
	''' or null if it is accepting input from any player. This is used to lock
	''' the game to a specific player profile. The main menu responds to input
	''' from any connected gamepad, but whichever player makes a selection from
	''' this menu is given control over all subsequent screens, so other gamepads
	''' are inactive until the controlling player returns to the main menu.
	''' </summary>
	Public Property ControllingPlayer As PlayerIndex?
		Get
			Return _controllingPlayer
		End Get
		Friend Set(value As PlayerIndex?)
			_controllingPlayer = value
		End Set
	End Property

	Dim _controllingPlayer As PlayerIndex?


	''' <summary>
	''' Gets the gestures the screen is interested in. Screens should be as specific
	''' as possible with gestures to increase the accuracy of the gesture engine.
	''' For example, most menus only need Tap or perhaps Tap and VerticalDrag to operate.
	''' These gestures are handled by the ScreenManager when screens change and
	''' all gestures are placed in the InputState passed to the HandleInput method.
	''' </summary>
	Public Property EnabledGestures As GestureType
		Get
			Return _enabledGestures
		End Get
		Protected Set(value As GestureType)
			_enabledGestures = value

			' the screen manager handles this during screen changes, but
			' if this screen is active and the gesture types are changing,
			' we have to update the TouchPanel ourself.
			If (ScreenState = ScreenState.Active) Then _
			 TouchPanel.EnabledGestures = value
		End Set
	End Property

	Dim _enabledGestures As GestureType = GestureType.None

	''' <summary>
	''' Gets whether or not this screen is serializable. If this is true,
	''' the screen will be recorded into the screen manager's state and
	''' its Serialize and Deserialize methods will be called as appropriate.
	''' If this is false, the screen will be ignored during serialization.
	''' By default, all screens are assumed to be serializable.
	''' </summary>
	Public Property IsSerializable As Boolean
		Get
			Return _isSerializable
		End Get
		Protected Set(value As Boolean)
			_isSerializable = value
		End Set
	End Property

	Dim _isSerializable As Boolean = True


#End Region

#Region "Initialization"


	''' <summary>
	''' Load graphics content for the screen.
	''' </summary>
	Public MustOverride Sub LoadContent()

	''' <summary>
	''' Unload content for the screen.
	''' </summary>
	Public MustOverride Sub UnloadContent()


#End Region

#Region "Update and Draw"


	''' <summary>
	''' Allows the screen to run logic, such as updating the transition position.
	''' Unlike HandleInput, this method is called regardless of whether the screen
	''' is active, hidden, or in the middle of a transition.
	''' </summary>
	Public Overridable Sub Update(GameTime As GameTime, otherScreenFocused As Boolean, _
   coveredByOtherScreen As Boolean)

		Me.otherScreenHasFocus = otherScreenFocused

		If (IsExiting) Then _
   ' If the screen is going away to die, it should transition off.
			ScreenState = ScreenState.TransitionOff

			If Not (UpdateTransition(GameTime, TransitionOffTime, 1)) Then
				' When the transition finishes, remove the screen.
				ScreenManager.RemoveScreen(Me)
			End If
		ElseIf (coveredByOtherScreen) Then
			' If the screen is covered by another, it should transition off.
			If (UpdateTransition(GameTime, TransitionOffTime, 1)) Then
				' Still busy transitioning.
				screenState = ScreenState.TransitionOff
			Else
				' Transition finished!
				ScreenState = ScreenState.Hidden
			End If
		Else
			' Otherwise the screen should transition on and become active.
			If (UpdateTransition(GameTime, TransitionOnTime, -1)) Then
				' Still busy transitioning.
				ScreenState = ScreenState.TransitionOn
			Else
				' Transition finished!
				ScreenState = ScreenState.Active
			End If
		End If
	End Sub


	''' <summary>
	''' Helper for updating the screen transition position.
	''' </summary>
	Function UpdateTransition(GameTime As GameTime, time As TimeSpan, direction%) As Boolean
		' How much should we move by?
		Dim _transitionDelta!

		If (time = TimeSpan.Zero) Then _
		 _transitionDelta = 1 _
		Else _
		_transitionDelta = CSng(GameTime.ElapsedGameTime.TotalMilliseconds / _
		  time.TotalMilliseconds)

		' Update the transition position.
		TransitionPosition += _transitionDelta * direction

		' Did we reach the end of the transition?
		If (((direction < 0) And (TransitionPosition <= 0)) Or _
		 ((direction > 0) And (TransitionPosition >= 1))) Then
			TransitionPosition = MathHelper.Clamp(TransitionPosition, 0, 1)
			Return False
		End If

		' Otherwise we are still busy transitioning.
		Return True
	End Function


	''' <summary>
	''' Allows the screen to handle user input. Unlike Update, this method
	''' is only called when the screen is active, and not when some other
	''' screen has taken the focus.
	''' </summary>
	Public MustOverride Sub HandleInput(input As InputState)


	''' <summary>
	''' This is called when the screen should draw itself.
	''' </summary>
	Public MustOverride Sub Draw(GameTime As GameTime)


#End Region

#Region "Public Methods"

	''' <summary>
	''' Tells the screen to serialize its state into the given stream.
	''' </summary>
	Public MustOverride Sub Serialize(stream As Stream)

	''' <summary>
	''' Tells the screen to deserialize its state from the given stream.
	''' </summary>
	Public MustOverride Sub Deserialize(stream As Stream)

	''' <summary>
	''' Tells the screen to go away. Unlike ScreenManager.RemoveScreen, which
	''' instantly kills the screen, this method respects the transition timings
	''' and will give the screen a chance to gradually transition off.
	''' </summary>
	Public Sub ExitScreen()
		If (TransitionOffTime = TimeSpan.Zero) Then
			' If the screen has a zero transition time, remove it immediately.
			ScreenManager.RemoveScreen(Me)
		Else
			' Otherwise flag that it should transition off and then exit.
			IsExiting = True
		End If
	End Sub


#End Region
End Class
